﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.PythonAnalysis
{

    /// <summary>
    /// Python 模块文件中包括哪些类、方法、全局变量等。
    /// </summary>
    public class PythonModelInfo
    {
        public string ModelName { get; set; }
        public string ModelPath { get; set; }
        public List<PythonElementInfo> Elements { get; } = new List<PythonElementInfo>();


        /// <summary>
        /// 从指定路径读取 Python 文件中元素的相关信息。
        /// </summary>
        /// <param name="modelPath"></param>
        /// <param name="pythonModelInfo"></param>
        public static void ReadElementInfos(string modelPath, ref PythonModelInfo pythonModelInfo)
        {
            if (File.Exists(modelPath) == false) return;
            var trimChars = new char[] { ' ', '\t', };

            var regComment = new Regex(@"^[\t ]{0,}#");  // 注释行
            var regVars = new Regex(@"^([a-zA-Z_\u4E00-\u9FA5][0-9a-zA-Z_\u4E00-\u9FA5]{0,})( {0,}, {0,}([a-zA-Z_\u4E00-\u9FA5][0-9a-zA-Z_\u4E00-\u9FA5]{0,})){0,}(?=( {0,}=))");  // 全局变量
            var regMethod = new Regex(@"(?<=(^def {1,}))([a-zA-Z_\u4E00-\u9FA5][0-9a-zA-Z_\u4E00-\u9FA5]{0,})(?=( {0,}\(.*?\)):)");
            var regClassMethod = new Regex(@"(?<=(^    def {1,}))([a-zA-Z_\u4E00-\u9FA5][0-9a-zA-Z_\u4E00-\u9FA5]{0,})(?=( {0,}\(.*?\)):)");
            var regClass = new Regex(@"(?<=(class {1,}))([a-zA-Z_\u4E00-\u9FA5][0-9a-zA-Z_\u4E00-\u9FA5]{0,})(?=( {0,}\(.*?\)):)");

            var lines = File.ReadAllLines(modelPath, Encoding.UTF8);

            PythonElementInfo previewClassElementInfo = null;

            foreach (var line in lines)
            {
                // ignore comment line
                if (regComment.Match(line).Success) continue;

                // global variable
                var varMatch = regVars.Match(line);
                if (varMatch.Success)
                {
                    var varPieces = varMatch.Value.Trim(trimChars).Split(new char[] { ' ', ',', }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var varPiece in varPieces)
                    {
                        pythonModelInfo.Elements.Add(new PythonElementInfo()
                        {
                            ElementType = PythonElementType.Var,
                            ElementName = varPiece,
                        });
                    }
                    continue;
                }

                // global method
                var methodMatch = regMethod.Match(line);
                if (methodMatch.Success)
                {
                    var newMethodInfo = new PythonElementInfo()
                    {
                        ElementType = PythonElementType.Method,
                        ElementName = methodMatch.Value,
                    };
                    var regMethodArgs = new Regex(@"\(.*\)");
                    var matchMethodArgs = regMethodArgs.Match(line);
                    if (matchMethodArgs.Success)
                    {
                        var argPieces = matchMethodArgs.Value.Split(new char[] { ',', }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var argPiece in argPieces)
                        {
                            var indexOfEMark = argPiece.IndexOf('=');
                            if (indexOfEMark <= 0)
                            {
                                newMethodInfo.SubElements.Add(new PythonElementInfo()
                                {
                                    ElementType = PythonElementType.Arg,
                                    ElementName = argPiece.Trim(trimChars),
                                });
                            }
                            else
                            {
                                newMethodInfo.SubElements.Add(new PythonElementInfo()
                                {
                                    ElementType = PythonElementType.Arg,
                                    ElementName = argPiece.Substring(0, indexOfEMark).Trim(trimChars),
                                });
                            }
                        }
                        pythonModelInfo.Elements.Add(newMethodInfo);
                    }
                }

                // python class
                var matchClass = regClass.Match(line);
                if (matchClass.Success)
                {
                    var newClassElementInfo = new PythonElementInfo()
                    {
                        ElementType = PythonElementType.Class,
                        ElementName = matchClass.Value,
                    };
                    previewClassElementInfo = newClassElementInfo;
                    pythonModelInfo.Elements.Add(newClassElementInfo);
                }

                // method in python class
                var classMethodMatch = regClassMethod.Match(line);
                if (classMethodMatch.Success)
                {
                    var newClassMethodInfo = new PythonElementInfo()
                    {
                        ElementType = PythonElementType.Method,
                        ElementName = methodMatch.Value,
                    };
                    var regMethodArgs = new Regex(@"\(.*\)");
                    var matchMethodArgs = regMethodArgs.Match(line);
                    if (matchMethodArgs.Success)
                    {
                        var argPieces = matchMethodArgs.Value.Split(new char[] { ',', }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var argPiece in argPieces)
                        {
                            var indexOfEMark = argPiece.IndexOf('=');
                            if (indexOfEMark <= 0)
                            {
                                newClassMethodInfo.SubElements.Add(new PythonElementInfo()
                                {
                                    ElementType = PythonElementType.Arg,
                                    ElementName = argPiece.Trim(trimChars),
                                });
                            }
                            else
                            {
                                newClassMethodInfo.SubElements.Add(new PythonElementInfo()
                                {
                                    ElementType = PythonElementType.Arg,
                                    ElementName = argPiece.Substring(0, indexOfEMark).Trim(trimChars),
                                });
                            }
                        }
                        previewClassElementInfo?.SubElements.Add(newClassMethodInfo);
                    }
                }
            }
        }
    }
}
